/**********************************************************************************************************
** 驱动文件：	ups-CP30KVA.c
** 驱动类型：	ups
** 设备名称：	力讯UPS
** 设备型号：	CP30KVA
** 设备品牌：	力讯
** 设备协议：	RS232通讯协议
** 驱动描述：	适用于力讯工频在线式CP系列UPS。
** 生成日期：	2020-08-22 19:48:57
**********************************************************************************************************/
#include "Includes.h"


/**********************************************************************************************************
* 定义设备数据点变量结构
**********************************************************************************************************/
typedef struct{
	Var InputUA;								//输入A相电压
	Var InputUB;								//输入B相电压
	Var InputUC;								//输入C相电压
	Var OutputUA;								//输出A相电压
	Var OutputUB;								//输出B相电压
	Var OutputUC;								//输出C相电压
	Var OutputLoadRateA;						//输出A相负载率
	Var OutputLoadRateB;						//输出B相负载率
	Var OutputLoadRateC;						//输出C相负载率
	Var Temperature;							//温度
	Var Frequency;								//频率
	Var BatteryVoltage;							//电池电压
	Var DischargeTime;							//放电时间
	Var RunningState;							//UPS运行状态
	Var OutputMode;								//输出方式
	Var MainsStatus;							//市电状态
	Var BatteryStatus;							//电池状态
	Var BatteryDischarge;						//电池放电
}Data_Struct;									//定义变量结构


/**********************************************************************************************************
* 设备数据点变量属性声明
**********************************************************************************************************/
const static Var_Property_Def var_attr[] = {
	{
		FLOAT,
		0,
		READONLY,
		"InputUA",
		"输入A相电压",
		"V",
		"输入A相电压",
		0,
		0,
		"输入A相电压过高",
		"输入A相电压过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"InputUB",
		"输入B相电压",
		"V",
		"输入B相电压",
		0,
		0,
		"输入B相电压过高",
		"输入B相电压过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"InputUC",
		"输入C相电压",
		"V",
		"输入C相电压",
		0,
		0,
		"输入C相电压过高",
		"输入C相电压过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"OutputUA",
		"输出A相电压",
		"V",
		"输出A相电压",
		0,
		0,
		"输出A相电压过高",
		"输出A相电压过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"OutputUB",
		"输出B相电压",
		"V",
		"输出B相电压",
		0,
		0,
		"输出B相电压过高",
		"输出B相电压过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"OutputUC",
		"输出C相电压",
		"V",
		"输出C相电压",
		0,
		0,
		"输出C相电压过高",
		"输出C相电压过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"OutputLoadRateA",
		"输出A相负载率",
		"%",
		"输出A相负载率",
		0,
		0,
		"输出A相负载率过高",
		"输出A相负载率过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"OutputLoadRateB",
		"输出B相负载率",
		"%",
		"输出B相负载率",
		0,
		0,
		"输出B相负载率过高",
		"输出B相负载率过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"OutputLoadRateC",
		"输出C相负载率",
		"%",
		"输出C相负载率",
		0,
		0,
		"输出C相负载率过高",
		"输出C相负载率过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"Temperature",
		"温度",
		"℃",
		"温度",
		0,
		0,
		"温度过高",
		"温度过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"Frequency",
		"频率",
		"Hz",
		"频率",
		0,
		0,
		"频率过高",
		"频率过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"BatteryVoltage",
		"电池电压",
		"V",
		"电池电压",
		0,
		0,
		"电池电压过高",
		"电池电压过低",
		0.000,
		0.000
	},
	{
		FLOAT,
		0,
		READONLY,
		"DischargeTime",
		"放电时间",
		"分",
		"放电时间",
		0,
		0,
		"放电时间充足",
		"放电时间不足",
		0.000,
		0.000
	},
	{
		OCTSTR,
		0,
		READONLY,
		"RunningState",
		"UPS运行状态",
		"",
		"UPS运行状态：0-正常；1-异常",
		0,
		0,
		"告警",
		"",
		0.000,
		0.000
	},
	{
		OCTSTR,
		0,
		READONLY,
		"OutputMode",
		"输出方式",
		"",
		"输出方式：0-逆变；1-旁路",
		0,
		0,
		"告警",
		"",
		0.000,
		0.000
	},
	{
		OCTSTR,
		0,
		READONLY,
		"MainsStatus",
		"市电状态",
		"",
		"市电状态：0-正常；1-掉电",
		0,
		0,
		"告警",
		"",
		0.000,
		0.000
	},
	{
		OCTSTR,
		0,
		READONLY,
		"BatteryStatus",
		"电池状态",
		"",
		"电池状态：0-正常；1-低压",
		0,
		0,
		"告警",
		"",
		0.000,
		0.000
	},
	{
		OCTSTR,
		0,
		READONLY,
		"BatteryDischarge",
		"电池放电",
		"",
		"电池放电：0-无；1-放电",
		0,
		0,
		"告警",
		"",
		0.000,
		0.000
	}
};


/**********************************************************************************************************
* 函数名称： static void cmd_fun(short index, int addr, void *data, char *cmd, short *len)
* 函数说明： 生成获取传感器数据指令
* 输入参数： 指令索引，传感器地址，变量结构体指针,以及指令缓存区指针,指令长度
* 返回参数： 无
**********************************************************************************************************/
static void cmd_fun(short index, int addr, void *data, char *cmd, short *len)
{
	switch(index)
	{
		case 0:
			*len = sprintf(cmd,"RS\r");
			break;
		case 1:
			*len = sprintf(cmd,"RD\r");
			break;		
		case 2:
			*len = sprintf(cmd,"RD\r");
			break;
		default:
			break;
	}
}


/**********************************************************************************************************
* 函数名称： static int parse_fun(short index, int addr, void *data, char *buf, short len)
* 函数说明： 解析传感器响应的数据，并写入数据库
* 输入参数： 解析索引,传感器地址，变量结构体指针，以及响应数据缓存取指针，响应数据长度
* 返回参数： 返回解析结果，返回0成功，返回1失败
**********************************************************************************************************/
static int parse_fun(short index, int addr, void *data, char *buf, short len)
{
	Data_Struct	*d = (Data_Struct*)data;
	char *p;
	if(buf!=NULL && len>0)
	{
		switch(index)
		{
			case 0:
				SetStringDataPoint(&d->RunningState,		(int)strstr(buf, "SOK1"), Alarm, Normal, "异常", "正常");
				SetStringDataPoint(&d->OutputMode,			(int)strstr(buf, "SBP1"), Alarm, Normal, "逆变", "逆变");
				SetStringDataPoint(&d->MainsStatus,			(int)strstr(buf, "SUF1"), Alarm, Normal, "掉电", "正常");
				SetStringDataPoint(&d->BatteryStatus,		(int)strstr(buf, "SBL1"), Alarm, Normal, "低压", "正常");
				SetStringDataPoint(&d->BatteryDischarge,	(int)strstr(buf, "SBM1"), Alarm, Normal, "放电", "无");
				break;
			case 1:					
			case 2:
				p = strstr(buf,"DVIA")+4;
				d->InputUA.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DVIB")+4;
				d->InputUB.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DVIC")+4;
				d->InputUC.value.fnum = p ? atof(p) : 0;
			
				p = strstr(buf,"DVOA")+4;
				d->OutputUA.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DVOB")+4;
				d->OutputUB.value.fnum = p ? atof(p) : 0;	
				p = strstr(buf,"DVOC")+4;
				d->OutputUC.value.fnum = p ? atof(p) : 0;

				p = strstr(buf,"DLOA")+4;
				d->OutputLoadRateA.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DLOB")+4;
				d->OutputLoadRateB.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DLOC")+4;
				d->OutputLoadRateC.value.fnum = p ? atof(p) : 0;
			
				p = strstr(buf,"DTMP")+4;
				d->Temperature.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DHZF")+4;
				d->Frequency.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DVBT")+4;
				d->BatteryVoltage.value.fnum = p ? atof(p) : 0;
				p = strstr(buf,"DTMB")+4;
				d->DischargeTime.value.fnum = p ? atof(p) : 0;
				break;
			default:
				break;
		}
		return 0;
	}
	return 1;
}


/**********************************************************************************************************
* 函数名称： void ups_CP30KVA_Registration(void)
* 函数说明： 力讯UPS驱动注册
* 输入参数： 无
* 返回参数： 无
**********************************************************************************************************/
void ups_CP30KVA_Registration(void)
{
	DeviceDriverRegistration(
		"ups",													//设备类型
		"力讯UPS",												//设备名称（导航栏默认显示名称）
		"力讯",													//设备品牌
		"CP30KVA",												//设备型号
		"适用于力讯工频在线式CP系列UPS。",					//驱动描述
		var_attr,												//变量属性声明
		sizeof(Data_Struct),									//变量结构体空间大小
		cmd_fun,												//发送指令生成函数
		parse_fun,												//数据解析函数
		1500													//设备响应超时时间
	);
#if 0 || VirtualFrameEN
	#define CMD1 "\x52\x53\x0D"
	#define RSP1 "\x53\x4F\x4B\x30\x0D\x0A\x53\x55\x46\x30\x0D\x0A\x53\x42\x50\x30\x0D\x0A\x53\x42\x4D\x31\x0D\x0A\x53\x42\x4C\x30"	
	#define CMD2 "\x52\x44\x0D"
	#define RSP2 "\x44\x56\x49\x41\x32\x32\x33\x0D\x0A\x44\x56\x49\x42\x32\x32\x32\x0D\x0A\x44\x56\x49\x43\x32\x32\x34\x0D\x0A\x44\x56\x4F\x41\x32\x32\x33\x0D\x0A\x44\x56\x4F\x42\x30\x30\x30\x0D\x0A\x44\x56\x4F\x43\x30\x30\x30\x0D\x0A\x44\x4C\x4F\x41\x30\x30\x30\x0D\x0A\x44\x4C\x4F\x42\x30\x30\x30\x0D\x0A\x44\x4C\x4F\x43\x30\x30\x30\x0D\x0A\x44\x54\x4D\x50\x30\x32\x35\x0D\x0A\x44\x48\x5A\x46\x30\x35\x30\x0D\x0A\x44\x56\x42\x54\x34\x33\x34\x0D\x0A\x44\x54\x4D\x42\x30\x31\x30"	
		
	VirtualFrameRegistration(CMD1, sizeof(CMD1)-1, RSP1, sizeof(RSP1)-1);
	VirtualFrameRegistration(CMD2, sizeof(CMD2)-1, RSP2, sizeof(RSP2)-1);
#endif
}

